package eu.smoothit.sis.admin.backendBean;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import eu.smoothit.sis.admin.backendBean.superclass.ComponentConfigAbstract;
import eu.smoothit.sis.db.impl.entities.ComponentConfigEntry;

public class MeteringConfigBean extends ComponentConfigAbstract {
	// initialization
	public MeteringConfigBean() {
		// add UI menu for BGP source selection
		ipRangeOptions = new ArrayList<SelectItem>();
		SelectItem option = new SelectItem(METERING_PROP_LOCAL_IP_INFO_SRC,
				"Local");
		ipRangeOptions.add(option);
		option = new SelectItem(METERING_PROP_REMOTE_IP_INFO_SRC, "Remote");
		ipRangeOptions.add(option);

	}

	// public void passPersistedValue_refreshRate() {
	// refreshRate_persisted = refreshRate;
	// }

	// Constants
	// ----------------------------------------------------------------------------------
	public static final String COMPONENT_NAME = "Metering";
	public static final String METERING_PROP_REFRESH_RATE = "Metering-Refresh-Rate";
	// source options for both remote and local
	public static final String METERING_VAL_IP_INFO_SRC_DB = eu.smoothit.sis.init.web.SisWebInitializer.METERING_VAL_IP_INFO_SRC_DB; // "DB";
	public static final String METERING_VAL_IP_INFO_SRC_ROUTER = eu.smoothit.sis.init.web.SisWebInitializer.METERING_VAL_IP_INFO_SRC_ROUTER; // "Router";
	public static final String METERING_VAL_IP_INFO_SRC_FILE = eu.smoothit.sis.init.web.SisWebInitializer.METERING_VAL_IP_INFO_SRC_FILE; // "File";
	public static final String initialSourceValueWhenNonSelected = "Select from left menu";
	// XX_BGP_XX:remote
	// XX_OSPF_XX: local
	// remote file
	public static final String METERING_PROP_BGP_FILE_NAME = eu.smoothit.sis.init.web.SisWebInitializer.METERING_PROP_BGP_FILE_NAME;// "Metering-BGP-File-Name";
	public static final String METERING_PROP_LOCAL_FILE_NAME = eu.smoothit.sis.init.web.SisWebInitializer.METERING_PROP_LOCAL_FILE_NAME;// "Metering-BGP-Local-File-Name";
	// Router

	public static final String METERING_PROP_BGP_ROUTER_ADDRESS = eu.smoothit.sis.init.web.SisWebInitializer.METERING_PROP_BGP_ROUTER_ADDRESS;// "Metering-BGP-Router-Address";
	public static final String METERING_PROP_BGP_ROUTER_PORT = eu.smoothit.sis.init.web.SisWebInitializer.METERING_PROP_BGP_ROUTER_PORT;// "Metering-BGP-Router-Port";
	public static final String METERING_PROP_BGP_ROUTER_SNMP_COMMUNITY = eu.smoothit.sis.init.web.SisWebInitializer.METERING_PROP_BGP_ROUTER_SNMP_COMMUNITY;// "Metering-BGP-Router-SNMP-Community";
	public static final String METERING_PROP_OSPF_ROUTER_ADDRESS = eu.smoothit.sis.init.web.SisWebInitializer.METERING_PROP_OSPF_ROUTER_ADDRESS;// "Metering-OSPF-Router-Address";
	public static final String METERING_PROP_OSPF_ROUTER_PORT = eu.smoothit.sis.init.web.SisWebInitializer.METERING_PROP_OSPF_ROUTER_PORT;// "Metering-OSPF-Router-Port";
	public static final String METERING_PROP_OSPF_ROUTER_SNMP_COMMUNITY = eu.smoothit.sis.init.web.SisWebInitializer.METERING_PROP_OSPF_ROUTER_SNMP_COMMUNITY;// "Metering-OSPF-Router-SNMP-Community";

	// Properties
	// if option local/remote and source(DB,File, Router)
	private boolean localFlag = false;
	private String source = "File"; // File, DB, Router

	Map<String, String> storedProperties = new HashMap<String, String>();
	private Map<String, String> cachedProperties = new HashMap<String, String>();
	// ---------------------------------------------------------------------------------------
	// refresh rate
	// private UIPanel refreshRatePanel;
	private String refreshRate;
	// private String refreshRate_persisted;
	// private boolean refreshRateEditable = false;
	// replaced with selectedIpRangOption
	private String ipRangeOption;
	private boolean ipRangeOptionSelected = false;
	private boolean ipRangeSourceEditable = false;
	private boolean ipRangeSourceValueReassigned = false;
	private String selectIpRangeOption;
	private String selectIpRangeOption_persisted;
	// private String selectIpRangeOption_old;
	// file path config related
	private String fileName;
	private String routerAddress;
	private String routerPort;
	private String routerSNMP;

	// ip range config
	private String selectIpRangeSource;
	private String selectIpRangeSource_persisted;
	// Router config parameters

	private static Collection<SelectItem> IpRangSources;
	static {
		IpRangSources = new ArrayList<SelectItem>();
		IpRangSources.add(new SelectItem(METERING_VAL_IP_INFO_SRC_DB));
		IpRangSources.add(new SelectItem(METERING_VAL_IP_INFO_SRC_FILE));
		IpRangSources.add(new SelectItem(METERING_VAL_IP_INFO_SRC_ROUTER));
	}

	private List<SelectItem> ipRangeOptions;

	// getter & setter-------------------------------------------------
	public String getRefreshRate() {
		// read all Metering parameters each time refresh page
		if (FacesContext.getCurrentInstance().getRenderResponse())
			readFromDB();
		return refreshRate;
	}

	public void setRefreshRate(String refreshRate) {
		this.refreshRate = refreshRate;

	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public String getRouterAddress() {
		return routerAddress;
	}

	public void setRouterAddress(String routerAddress) {
		this.routerAddress = routerAddress;
	}

	public String getRouterPort() {
		return routerPort;
	}

	public void setRouterPort(String routerPort) {
		this.routerPort = routerPort;
	}

	public String getRouterSNMP() {
		return routerSNMP;
	}

	public void setRouterSNMP(String routerSNMP) {
		this.routerSNMP = routerSNMP;
	}

	public void setIpRangeOptions(List<SelectItem> ipRangeOptions) {
		this.ipRangeOptions = ipRangeOptions;
	}

	public List<SelectItem> getIpRangeOptions() {
		return ipRangeOptions;
	}

	public boolean getIpRangeSourceEditable() {
		return ipRangeSourceEditable;
	}

	// replaced with selectIpRangeSource
	private String ipRangeSource; // TODO to cie ipRangeSouce the second?

	public String getIpRangeOption() {
		return ipRangeOption;
	}

	public void setIpRangeOption(String ipRangeOption) {
		this.ipRangeOption = ipRangeOption;
	}

	public String getSelectIpRangeOption() {
		return selectIpRangeOption;
	}

	public void setSelectIpRangeOption(String selectIpRangeOption) {
		this.selectIpRangeOption = selectIpRangeOption;
	}

	public String getIpRangeSource() {

		return ipRangeSource;
	}

	public void setIpRangeSource(String ipRangeSource) {
		this.ipRangeSource = ipRangeSource;
	}

	public Collection<SelectItem> getIpRangeSources() {
		if (selectIpRangeOption != null && selectIpRangeOption.length() > 0) {
			return IpRangSources;
		} else {
			Collection<SelectItem> nullOption = new ArrayList<SelectItem>();
			nullOption.add(new SelectItem(initialSourceValueWhenNonSelected));
			return nullOption;
		}
	}

	public boolean isIpRangeSourceValueReassigned() {
		return ipRangeSourceValueReassigned;
	}

	public void setIpRangeSourceValueReassigned(
			boolean ipRangeSourceValueReassigned) {
		this.ipRangeSourceValueReassigned = ipRangeSourceValueReassigned;
	}

	// file path

	public String getSelectIpRangeSource() {
		// if(selectIpRangeSource!=null && selectIpRangeSource.length()>0)
		// selectIpRangeSource = searchComponentConfigEntry(COMPONENT_NAME,
		// selectIpRangeOption);
		return selectIpRangeSource;
	}

	public void setSelectIpRangeSource(String selectIpRangeSource) {
		this.selectIpRangeSource = selectIpRangeSource;
	}

	// Router config

	// ----------------------------------------------------------------------------

	// TODO, show save button only when valuechangelistener of
	// selectIpRangeSource changed
	public void saveIpRangOptionWithIpRangeSource() {
		if (selectIpRangeSource != null && selectIpRangeSource.length() > 0) {
			saveComponentConfigEntry(COMPONENT_NAME, selectIpRangeOption,
					selectIpRangeSource);
			selectIpRangeSource_persisted = selectIpRangeSource;
			setErrorMessage(selectIpRangeOption + " now is associated to "
					+ selectIpRangeSource);
		}
		// always reset save button
		ipRangeSourceValueReassigned = false;
	}

	public void cancelIpRangOptionWithIpRangeSource() {
		// refresh
		// if (selectIpRangeOption_old != null
		// && selectIpRangeOption_old.length() > 0)
		// selectIpRangeSource = selectIpRangeOption_old;
		selectIpRangeSource = selectIpRangeSource_persisted;
		ipRangeSourceValueReassigned = false;
	}

	// public boolean isRefreshRateEditable() {
	// return refreshRateEditable;
	// }

	public boolean isIpRangeSourceEditable() {
		return ipRangeSourceEditable;
	}

	public boolean isIpRangeOptionSelected() {
		return ipRangeOptionSelected;
	}

	public void setIpRangeOptionSelected(boolean ipRangeOptionSelected) {
		this.ipRangeOptionSelected = ipRangeOptionSelected;
	}

	// Form actions
	// -------------------------------------------------------------------------------

	public void editIpRangeSource() {
		ipRangeSourceEditable = true;
	}

	public void cancelIpRangeSourceChange() {
		ipRangeSourceEditable = false;
	}

	// Listener
	// -----------------------------------------------------------------

	public void ipRangeOptionChangeListener(ValueChangeEvent event) {
		selectIpRangeOption = (String) event.getNewValue();
		selectIpRangeSource = searchComponentConfigEntry(COMPONENT_NAME,
				selectIpRangeOption);
		// update new assigned source after save source and not switch option
		selectIpRangeSource_persisted = selectIpRangeSource;
		// reserve current source for the selected option
		selectIpRangeOption_persisted = (String) event.getOldValue();
		// disable save button when swtich option
		if (selectIpRangeOption_persisted == null
				|| !selectIpRangeOption_persisted.equals(selectIpRangeOption))
			ipRangeSourceValueReassigned = false;

		// force to refresh
		if (!event.getPhaseId().equals(PhaseId.INVOKE_APPLICATION)) {
			event.setPhaseId(PhaseId.INVOKE_APPLICATION);
			event.queue();
			return;
		}
	}

	public void ipRangeSourceChangeListener(ValueChangeEvent event) {

		String selectedIpRangSourceValue = (String) event.getNewValue();
		// if source value changed and original source value is not null(stand
		// for not )
		if ((!selectedIpRangSourceValue.equals(selectIpRangeSource_persisted))
				&& !selectedIpRangSourceValue
						.equals(initialSourceValueWhenNonSelected)) {
			// enable save button when select new source for the same option
			ipRangeSourceValueReassigned = true;
		}
		// disable Save button when reselect original source
		else
			ipRangeSourceValueReassigned = false;
		// advance submit progress
		advanceSubmit(event);
	}

	/**
	 * assign retrievaled params to UI inputs if contained used on initial and
	 * cancelsave
	 */
	public void restoreValues() {
		for (Map.Entry<String, String> e : storedProperties.entrySet()) {
			// TODO add source(db, file, router)
			if (localFlag) {
				if (e.getKey().equals(METERING_PROP_LOCAL_FILE_NAME)) {
					fileName = e.getValue();
				} else if (e.getKey().equals(METERING_PROP_OSPF_ROUTER_ADDRESS)) {
					routerAddress = e.getValue();
				} else if (e.getKey().equals(METERING_PROP_OSPF_ROUTER_PORT)) {
					routerPort = e.getValue();
				} else if (e.getKey().equals(
						METERING_PROP_OSPF_ROUTER_SNMP_COMMUNITY)) {
					routerSNMP = e.getValue();
				}
			} else {
				if (e.getKey().equals(METERING_PROP_BGP_FILE_NAME)) {
					fileName = e.getValue();
				} else if (e.getKey().equals(METERING_PROP_BGP_ROUTER_ADDRESS)) {
					routerAddress = e.getValue();
				} else if (e.getKey().equals(METERING_PROP_BGP_ROUTER_PORT)) {
					routerPort = e.getValue();
				} else if (e.getKey().equals(
						METERING_PROP_BGP_ROUTER_SNMP_COMMUNITY)) {
					routerSNMP = e.getValue();
				}
			}
		}
	}

	/**
	 * retrieval parameters if existed in DB and show on UI used on init, after
	 * saveProperties is stored params Map
	 */
	public void readFromDB() {
		ComponentConfigEntry ConfigEntry = new ComponentConfigEntry();
		ConfigEntry.setComponent(COMPONENT_NAME);
		List<ComponentConfigEntry> storedConfigEntries = dataDAO
				.get(ConfigEntry);
		storedProperties.clear();
		for (ComponentConfigEntry e : storedConfigEntries) {
			storedProperties.put(e.getPropName(), (String) e.getValue());
		}
		restoreValues();

	}

	/**
	 * read input from UI and store into a temp MAP
	 */
	public void retrieveInput() {
		cachedProperties.put(METERING_PROP_REFRESH_RATE, refreshRate);
		if (source.equals("File")) {
			if (localFlag) {
				cachedProperties.put(METERING_PROP_LOCAL_FILE_NAME, fileName);
			} else {
				cachedProperties.put(METERING_PROP_BGP_FILE_NAME, fileName);
			}
		} else if (source.equals("Router")) {
			if (localFlag) {
				cachedProperties.put(METERING_PROP_OSPF_ROUTER_ADDRESS,
						routerAddress);
				cachedProperties
						.put(METERING_PROP_OSPF_ROUTER_PORT, routerPort);
				cachedProperties.put(METERING_PROP_OSPF_ROUTER_SNMP_COMMUNITY,
						routerSNMP);
			} else {
				cachedProperties.put(METERING_PROP_BGP_ROUTER_ADDRESS,
						routerAddress);
				cachedProperties.put(METERING_PROP_BGP_ROUTER_PORT, routerPort);
				cachedProperties.put(METERING_PROP_BGP_ROUTER_SNMP_COMMUNITY,
						routerSNMP);

			}
		}
	}

	public void saveChange() {
		retrieveInput();
		String property;
		String value;
		String feedback_deleted = "";
		String feedback_updated = "";
		String feedback_add = "";
		ComponentConfigEntry ConfigEntry;
		for (Map.Entry<String, String> valuePair : cachedProperties.entrySet()) {
			property = valuePair.getKey();
			value = valuePair.getValue();
			// property exist
			if (storedProperties.containsKey(property)) {
				// value is empty, remove the property
				if (value.length() == 0) {
					ConfigEntry = new ComponentConfigEntry();
					ConfigEntry.setComponent(COMPONENT_NAME);
					ConfigEntry.setPropName(property);
					storedProperties.remove(ConfigEntry);
					try {
						ConfigEntry = dataDAO.get(ConfigEntry).get(0);
						dataDAO.remove(ConfigEntry);
					} catch (Exception e) {
						setErrorMessage(e.getMessage() + " Cause: "
								+ e.getCause());
						e.printStackTrace();
					}
					feedback_deleted = feedback_deleted + property + ";";
				}
				// value is not changed, return
				else if (storedProperties.get(property).equals(value)) {
					// feedback=feedback+"no change:" + property+"\n" ;
				}
				// value change, update
				else {
					ConfigEntry = new ComponentConfigEntry();
					ConfigEntry.setComponent(COMPONENT_NAME);
					ConfigEntry.setPropName(property);
					storedProperties.put(property, value);
					try {
						ConfigEntry = dataDAO.get(ConfigEntry).get(0);
						ConfigEntry.setValue(value);
						dataDAO.update(ConfigEntry);
						feedback_updated = feedback_updated + property + ";";
					} catch (Exception e) {
						setErrorMessage(e.getMessage() + " Cause: "
								+ e.getCause());
						e.printStackTrace();
					}
				}

			}
			// add new property
			else if (value.length() > 0) {
				ConfigEntry = new ComponentConfigEntry(COMPONENT_NAME,
						property, value);
				System.err.println("iop persist new:" + property + value);
				storedProperties.put(property, value);
				try {
					dataDAO.persist(ConfigEntry);
				} catch (Exception e) {
					setErrorMessage(e.getMessage() + " Cause: " + e.getCause());
					e.printStackTrace();
				}
				feedback_add = feedback_add + property + ";";
			}

		}
		// reset
		cachedProperties.clear();
		String feedback_total = "";
		if (feedback_add.length() > 0)
			feedback_total = feedback_total + "Added:" + feedback_add + "<br>";
		if (feedback_deleted.length() > 0)
			feedback_total = feedback_total + "Deleted:" + feedback_deleted
					+ "<br>";
		if (feedback_updated.length() > 0)
			feedback_total = feedback_total + "Updated:" + feedback_updated
					+ "<br>";
		if (feedback_total.length() > 0)
			setErrorMessage(feedback_total);
		else
			setErrorMessage("NO Change submitted");
	}

	public void cancelChange() {
		// restore view using persisted value in DB.
		restoreValues();
		refreshPage();
	}

}
